
#include "Parser.c"
#include <stdio.h>


uint8_t myMac[6] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
uint8_t myIP[4] = {0x01, 0x02, 0x03, 0x04};

void handleIP( uint8_t *, uint32_t );
void handleArp( uint8_t *, uint32_t );


int sequencesNotEqual( uint8_t * seq1, uint8_t * seq2, int len ) {

  int i;
  for (i = 0; i < len; i++) {
    if ( seq1[i] != seq2[i] ) {
      return 1;
    }
  }
  return 0;

}

void handlePacket( uint8_t * p, uint32_t len ) {

  ethernetHeader h;
  memcpy( h.data, p, 14 );
  parseEthernet( &h );
  if ( sequencesNotEqual( h.dest, myMac, 6 ) ) {
    // Ethernet packet not destined for this interface
    return;
  }
  if ( h.arp_flag ) {
    handleArp( p, len );
  }
  else if ( h.ip_flag ) {
    handleIP( p, len );
  }
  else {
    // Protocol is not an Arp or IP
    return;
  }
  return;
  

}

void handleArp( uint8_t * p, uint32_t len ) {

  // Arp will start 14 bytes into the packet
  arpHeader h;
  memcpy( h.data, &p[14], 28 );
  parseArp( &h );
  if ( h.operation == 1 ) { // Request
    if ( sequencesNotEqual( h.receiverIP, myIP, 4 ) ) {
      // Ignore - Arp not for me
    }
    else {
      arpHeader outgoing;
      arpResponse( &outgoing, myMac, h.senderAddr, myIP, h.senderIP );
      // TODO - Tack on an ethernet header and send this
    }
  }
  else if ( h.operation == 2 ) { // Response
    // TODO - insert (h.senderIP, h.senderAddr) into ARP cache
  }
  else {
    printf("\nReceived malformed Arp packet. Neither request nor response.");
  }

}


void handleIP( uint8_t * p, uint32_t len ) {

  ipHeader incoming;
  // IP Header starts at offset of 14 bytes
  memcpy( incoming.header, &p[14], 20 );
  parseIP( &incoming );

  // TODO - decrement the TTL, and recompute the checksum

  if ( sequencesNotEqual( incoming.destIP, myIP, 4 ) ) {
    // TODO - look up the destination IP in the ARP cache

    // TODO - modify the ethernet header

    // TODO - forward it on to the next hop

  }

  else {
    // Destined for me
    int notPing = 0;
    if ( incoming.protocol == 1 ) {
      // ICMP Packet
      int icmpStart = 14 + incoming.headerLen;
      icmpHeader incoming_icmp;
      memcpy( incoming_icmp.data, &p[icmpStart], 8 );
      parseICMP( &incoming_icmp );
      if ( incoming_icmp.type == 8 && incoming_icmp.code == 0 ) {
	// ICMP Ping
	icmpHeader outgoing_icmp;
	icmpProtocolUnreachable ( &outgoing_icmp );
	ipHeader outgoing_ip;
	constructIP( &outgoing_ip, myIP, incoming.srcIP,
		     // TODO - figure out total length of packet,
		     incoming.totalLength, 65, 1 );
	// TODO - construct ethernet packet and send it out
      }
      else {
	notPing = 1;
      }
    }
    else {
      notPing = 1;
    }

    if ( notPing ) {
      icmpHeader outgoing_icmp;
      icmpProtocolUnreachable ( &outgoing_icmp );
      ipHeader outgoing_ip;
      constructIP( &outgoing_ip, myIP, incoming.srcIP,
		   // TODO - figure out total length of packet,
		   incoming.totalLength, 65, 1 );
      // TODO - construct ethernet packet and send it out
    
      
    }
  } /* Destined for my IP address */

}
